/**
 * @ Author: luoqi
 * @ Create Time: 2025-05-08 16:03
 * @ Modified by: luoqi
 * @ Modified time: 2025-05-22 15:19
 * @ Description:
 */

#pragma once
#ifndef _QLOG_HPP_
#define _QLOG_HPP_

#include <memory>
#include <string>
#include <ctime>
#include <iostream>
#include <utility>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/rotating_file_sink.h>

namespace QLog {
    // log in console
    template <typename... Args>
    inline void trace(spdlog::format_string_t<Args...> fmt, Args &&...args)
    {
        spdlog::trace(fmt, std::forward<Args>(args)...);
        std::printf("\r");
        std::fflush(stdout);
    }

    template <typename... Args>
    inline void dbg(spdlog::format_string_t<Args...> fmt, Args &&...args)
    {
        spdlog::debug(fmt, std::forward<Args>(args)...);
        std::printf("\r");
        std::fflush(stdout);
    }

    template <typename... Args>
    inline void info(spdlog::format_string_t<Args...> fmt, Args &&...args)
    {
        spdlog::info(fmt, std::forward<Args>(args)...);
        std::printf("\r");
        std::fflush(stdout);
    }

    template <typename... Args>
    inline void warn(spdlog::format_string_t<Args...> fmt, Args &&...args)
    {
        spdlog::warn(fmt, std::forward<Args>(args)...);
        std::printf("\r");
        std::fflush(stdout);
    }

    template <typename... Args>
    inline void err(spdlog::format_string_t<Args...> fmt, Args &&...args)
    {
        spdlog::error(fmt, std::forward<Args>(args)...);
        std::printf("\r");
        std::fflush(stdout);
    }

    template <typename... Args>
    inline void crit(spdlog::format_string_t<Args...> fmt, Args &&...args)
    {
        spdlog::critical(fmt, std::forward<Args>(args)...);
        std::printf("\r");
        std::fflush(stdout);
    }

    using lvl = spdlog::level::level_enum;

    inline void set_lvl(lvl level)
    {
        spdlog::set_level(level);
    }

    inline void set_fmt(std::string pattern)
    {
        spdlog::set_pattern(pattern);
    }

    class Logger {
    private:
        std::shared_ptr<spdlog::logger> logger;
        std::shared_ptr<spdlog::sinks::rotating_file_sink_mt> sink;
    public:
        Logger(const char *filename, const char *header,
            lvl level = lvl::info,
            const std::string fmt = "[%Y%m%d%H%M%S.%e](%n)<%L> %v",
            const std::string local = ".log",
            std::size_t max_size = 1024 * 1024 * 10,
            std::size_t max_files = 10)
        {
            time_t now;
            time(&now);
            struct tm *tm_info = localtime(&now);
            char buf[60] = { 0 };
            strftime(buf, 60, "%Y%m%d%H%M%S", tm_info);
            std::string log_file_name = local + "/" + std::string(filename) + "-" + buf + ".log";
            sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(log_file_name, max_size, max_files);
            logger = std::make_shared<spdlog::logger>(header, sink);
            logger->set_level(level);
            logger->set_pattern(fmt);
            logger->flush_on(level);
        }
        ~Logger() = default;
    public:
        void  set_lvl(lvl level)
        {
            logger->set_level(level);
        }

        void set_fmt(std::string pattern)
        {
            logger->set_pattern(pattern);
        }

        // logger in log file
        template <typename... Args>
        void trace(spdlog::format_string_t<Args...> fmt, Args &&...args)
        {
            logger->trace(fmt, std::forward<Args>(args)...);
        }

        template <typename... Args>
        void dbg(spdlog::format_string_t<Args...> fmt, Args &&...args)
        {
            logger->debug(fmt, std::forward<Args>(args)...);
        }

        template <typename... Args>
        void info(spdlog::format_string_t<Args...> fmt, Args &&...args)
        {
            logger->info(fmt, std::forward<Args>(args)...);
        }

        template <typename... Args>
        void warn(spdlog::format_string_t<Args...> fmt, Args &&...args)
        {
            logger->warn(fmt, std::forward<Args>(args)...);
        }

        template <typename... Args>
        void err(spdlog::format_string_t<Args...> fmt, Args &&...args)
        {
            logger->error(fmt, std::forward<Args>(args)...);
        }

        template <typename... Args>
        void crit(spdlog::format_string_t<Args...> fmt, Args &&...args)
        {
            logger->critical(fmt, std::forward<Args>(args)...);
        }

        // logger in log file and console
        template <typename... Args>
        void trace_c(const char *fmt, Args &&...args)
        {
            logger->trace(fmt, std::forward<Args>(args)...);
            QLog::trace(fmt, std::forward<Args>(args)...);
        }

        template <typename... Args>
        void dbg_c(spdlog::format_string_t<Args...> fmt, Args &&...args)
        {
            logger->debug(fmt, std::forward<Args>(args)...);
            QLog::dbg(fmt, std::forward<Args>(args)...);
        }

        template <typename... Args>
        void info_c(spdlog::format_string_t<Args...> fmt, Args &&...args)
        {
            logger->info(fmt, std::forward<Args>(args)...);
            QLog::info(fmt, std::forward<Args>(args)...);
        }

        template <typename... Args>
        void warn_c(spdlog::format_string_t<Args...> fmt, Args &&...args)
        {
            logger->warn(fmt, std::forward<Args>(args)...);
            QLog::warn(fmt, std::forward<Args>(args)...);
        }

        template <typename... Args>
        void err_c(spdlog::format_string_t<Args...> fmt, Args &&...args)
        {
            logger->error(fmt, std::forward<Args>(args)...);
            QLog::err(fmt, std::forward<Args>(args)...);
        }

        template <typename... Args>
        void crit_c(spdlog::format_string_t<Args...> fmt, Args &&...args)
        {
            logger->critical(fmt, std::forward<Args>(args)...);
            QLog::crit(fmt, std::forward<Args>(args)...);
        }
    };
}

#endif /* _QLOG_ */
